﻿using NetHelperCore;
using SiMay.Sockets.Tcp.Session;
using System.Buffers;
using System.Collections.Concurrent;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.IO;
using System.Net;
using System.Text;
using System.Text.Unicode;

namespace SyncFileCommon.Class
{
    public class SessionHelper
    {
        /// <summary>
        /// 分包数据缓存
        /// </summary>
        public static ConcurrentDictionary<long, byte[]> DataMultiplePackList = new ConcurrentDictionary<long, byte[]>();

        /// <summary>
        /// 数据包类型
        /// </summary>
        public enum DataPackType
        {
            /// <summary>
            /// 数据异常
            /// </summary>
            [Description("数据异常")] DataError = -9999,
            /// <summary>
            /// 单数据包
            /// </summary>
            [Description("单数据包")] DataOnePack = 10,
            /// <summary>
            /// 多数据包
            /// </summary>
            [Description("多数据包")] DataMultiplePack = 20,
            /// <summary>
            /// 多数据包接收成功，请求下一个数据包
            /// </summary>
            [Description("多数据包接收成功，请求下一个数据包")] DataMultiplePackRequest = 21,
            /// <summary>
            /// 待发送文件信息
            /// </summary>
            [Description("待发送文件信息")] FileInfo = 30,
            /// <summary>
            /// 文件包接收成功，请求下一个文件包
            /// </summary>
            [Description("文件包接收成功，请求下一个文件包")] FileDataPackRequest = 31,
            /// <summary>
            /// 文件内容数据包
            /// </summary>
            [Description("文件内容数据包")] FileDataPack = 32,
            /// <summary>
            /// 文件包下载服务缓存超时已释放
            /// </summary>
            [Description("文件包下载服务缓存超时已释放")] FileDataTimeOut = 33,
        }


        /// <summary>
        /// 最大单个数据包大小，必须大于25
        /// </summary>
        public static int DataPackSize = 1024 * 512;
        //public static int DataPackSize = 2048 * 512; 

        /// <summary>
        /// 文件下载缓存大小
        /// </summary>
        public static int FileCacheDataSize = 1024 * 1024;


        /// <summary>
        /// /// <summary>
        /// 发送数据
        /// </summary>
        /// <param name="session">Session</param>
        /// <param name="data">数据</param>
        /// <param name="id">数据包的唯一ID，当分包发送时，用于在缓存中获取发送完整数据</param>
        /// <param name="dataPosition">当分包发送时，已发送数据长度</param>
        public static void SendData(TcpSocketSaeaSession session, byte[] data, long id = -1, long dataPosition = -1)
        {
            byte[] _dataBuff = null;
            long _sendSize = 0;//已发送数据长度
            int _dataPackSize = 0;//当前发送数据包的数据长度

            //如果id>-1说明是发送分包的数据
            if (id > -1)
            {
                data = CacheHelper.CacheGet("SendData" + Convert.ToString(id)) as byte[];
                if (data == null)
                {
                    //如果缓存中没找到待发送数据则退出发送
                    return;
                }
                _sendSize = dataPosition;
                int _packSize = 0;//当前发送包的长度  
                if ((data.Length - _sendSize) >= (DataPackSize - 1 - sizeof(Int64) - sizeof(Int64)))
                {
                    //剩余数据长度大于一个包可发送的数据长度
                    _packSize = DataPackSize;
                }
                else
                {
                    _packSize = (int)(data.Length - _sendSize) + 1 + sizeof(Int64) + sizeof(Int64);
                }

                //第二个包开始发送包格式:拆分标识+唯一编号(雪花ID)+数据起始位置+包数据  
                _dataBuff = new byte[_packSize];

                //标记为分包发送数据
                _dataBuff[0] = Convert.ToByte(DataPackType.DataMultiplePack);
                //标记唯一编号
                BitConverter.GetBytes(id).CopyTo(_dataBuff, 1);
                //标记数据起始位置
                BitConverter.GetBytes(_sendSize).CopyTo(_dataBuff, 1 + sizeof(Int64));
                //发送数据的长度
                _dataPackSize = _packSize - 1 - sizeof(Int64) - sizeof(Int64);
                //将data的数据从起始位拷贝到_dataBuff中
                Array.Copy(data, _sendSize, _dataBuff, _packSize - _dataPackSize, _dataPackSize);
#if DEBUG
                Console.WriteLine("拆包发送数据，ID：" + Convert.ToString(id) + ",发送位置:" + _sendSize + ",发送长度:" + _dataPackSize);
#endif
                //发送分包数据
                session.SendAsync(_dataBuff);
                _dataBuff = null;
                return;
            }


            if (data.Length > (DataPackSize - (1 + sizeof(Int32))))
            {
                //如果数据大于一个数据表的大小，则分包发送 
                long _id = CommonHelper.GetNewID();//数据唯一ID

                //拆包发送
                //第一个包发送包格式:拆分标识+唯一编号(雪花ID)+数据起始位置+总包长+首包数据 
                _dataBuff = new byte[DataPackSize];
                //标记为分包发送数据
                _dataBuff[0] = Convert.ToByte(DataPackType.DataMultiplePack);
                //标记唯一编号
                BitConverter.GetBytes(_id).CopyTo(_dataBuff, 1);
                //标记数据起始位置
                BitConverter.GetBytes(0).CopyTo(_dataBuff, 1 + sizeof(Int64));
                //标记数据包总长度
                BitConverter.GetBytes(data.Length).CopyTo(_dataBuff, 1 + sizeof(Int64) + sizeof(Int64));
                //首包发送数据的长度
                _dataPackSize = DataPackSize - 1 - sizeof(Int64) - sizeof(Int64) - sizeof(Int64);
                Array.Copy(data, 0, _dataBuff, DataPackSize - _dataPackSize, _dataPackSize);
#if DEBUG
                LogHelper.WriteLogToFile("Socket", DateTime.Now.ToString("HH:mm:ss.fff") + " " + "开始拆包发送，ID：" + Convert.ToString(_id) + ",数据总大小:" + data.Length);
#endif
                session.SendAsync(_dataBuff);
                _sendSize += _dataPackSize;
                _dataBuff = null;
                CacheHelper.CacheAdd("SendData" + Convert.ToString(_id), data, null, 60);

            }
            else
            {
                //单包发送,数据包格式：包类型+数据长度+数据内容
                _dataBuff = new byte[1 + sizeof(Int32) + data.Length];
                //标记为单包数据
                _dataBuff[0] = Convert.ToByte(DataPackType.DataOnePack);
                //标记数据长度
                BitConverter.GetBytes(data.Length).CopyTo(_dataBuff, 1);
                Array.Copy(data, 0, _dataBuff, (1 + sizeof(Int32)), data.Length);
                session.SendAsync(_dataBuff);
            }
        }



        /// <summary>
        /// 发送文件
        /// </summary>
        /// <param name="session">Session</param>
        /// <param name="filePath">文件路径</param> 
        /// <param name="dataPosition">发送文件数据起始位置，如果为-1则为发送文件确认信息</param> 
        /// <returns>发送任务唯一编号</returns>
        public static long SendFile(TcpSocketSaeaSession session, string filePath, long id = -1, long dataPosition = -1)
        {
            if (!File.Exists(filePath))
            {
                throw new Exception("[" + filePath + "]文件不存在,无法发送");
            }

            FileDownloadInfo _fileDownloadInfo  = CacheHelper.CacheGet("FileDownloadInfo_" + id) as FileDownloadInfo;
            //如果缓存中没有，则初始化缓存
            if (_fileDownloadInfo == null)
            {
                _fileDownloadInfo = new FileDownloadInfo();
                //id为本次传输文件的唯一ID
                if (id == -1)
                {
                    _fileDownloadInfo.ID = CommonHelper.GetNewID();//数据唯一ID;
                }
                else
                {
                    _fileDownloadInfo.ID = id;
                }
                //保存服务器文件路径
                _fileDownloadInfo.ServerFilePath = filePath;
                //保持服务器文件流
                _fileDownloadInfo.FileDownloadStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read);
                // 获取文件大小
                _fileDownloadInfo.FileSize = _fileDownloadInfo.FileDownloadStream.Length;
                //如果是大文件获取文件MD5值，传输完毕客户端做MD5校验（因为对速度影响太大，暂时屏蔽）
                if (_fileDownloadInfo.FileSize > DataPackSize)
                {
                    //_fileDownloadInfo.FileMD5 = FileHelper.FileMD5(filePath);
                }
                //文件最后修改时间
                _fileDownloadInfo.LastModifiedTime = FileHelper.GetFileModifiedTime(filePath);
            }
            //缓存文件信息，用于再次请求文件分包数据时获取文件流，如果5分钟没有读取则自动释放
            CacheHelper.CacheAdd("FileDownloadInfo_" + _fileDownloadInfo.ID, _fileDownloadInfo, null, 60 * 5, (cacheKey, cacheValue) =>
            {
                //释放缓存时关闭文件流
                _fileDownloadInfo = cacheValue as FileDownloadInfo;
                if (_fileDownloadInfo.FileDownloadStream != null)
                {
                    _fileDownloadInfo.FileDownloadStream.Close();
                }
            });


            //dataPosition为-1则表明服务器准备向客户端发送文件数据请求，客户端接收到请求后需要设置保存文件路径
            if (dataPosition == -1)
            {
                //第一次发送，将文件的信息发送给接收端 
                string _fileInfo = new JsonHelper()
                    .AddVar("FilePath", _fileDownloadInfo.ServerFilePath)
                    .AddVar("LastModifiedTime", _fileDownloadInfo.LastModifiedTime).JsonStr;
                byte[] _bFileInfo = Encoding.UTF8.GetBytes(_fileInfo);
                byte[] _dataBuff = new byte[1 + sizeof(Int64) + sizeof(Int64) + _bFileInfo.Length];
                //发送给文件接收端文件信息数据，文件接收端设置好文件保存路径后再返回请求文件内容分包数据
                _dataBuff[0] = Convert.ToByte(DataPackType.FileInfo);
                //标记唯一编号
                BitConverter.GetBytes(_fileDownloadInfo.ID).CopyTo(_dataBuff, 1);
                //发送文件总大小
                BitConverter.GetBytes(_fileDownloadInfo.FileSize).CopyTo(_dataBuff, 1 + sizeof(Int64));

                Array.Copy(_bFileInfo, 0, _dataBuff, 1 + sizeof(Int64) + sizeof(Int64), _bFileInfo.Length);
                //给客户端发送准备下载文件的数据包
                session.SendAsync(_dataBuff);
            }
            else
            {
                byte[] _dataBuff = null;
                long _fileDataSize = 0;
                //判断一个数据包是否能传输完
                if (DataPackSize - (1 + sizeof(Int64) + sizeof(Int64)) > _fileDownloadInfo.FileSize - dataPosition)
                {
                    _fileDataSize = _fileDownloadInfo.FileSize - dataPosition;

                }
                else
                {
                    _fileDataSize = DataPackSize - (1 + sizeof(Int64) + sizeof(Int64));
                }

                byte[] _fileData = new byte[_fileDataSize];
                // 将文件读到byte数组中
                _fileDownloadInfo.FileDownloadStream.Seek(dataPosition, SeekOrigin.Begin);
                _fileDownloadInfo.FileDownloadStream.Read(_fileData, 0, _fileData.Length);

                _dataBuff = new byte[1 + sizeof(Int64) + sizeof(Int64) + _fileDataSize];
                _dataBuff[0] = Convert.ToByte(DataPackType.FileDataPack);
                BitConverter.GetBytes(_fileDownloadInfo.ID).CopyTo(_dataBuff, 1);
                BitConverter.GetBytes(dataPosition).CopyTo(_dataBuff, 1 + sizeof(Int64));
                Array.Copy(_fileData, 0, _dataBuff, 1 + sizeof(Int64) + sizeof(Int64), _fileData.Length);
                session.SendAsync(_dataBuff);
            }


            return _fileDownloadInfo.ID;
        }


        /// <summary>
        /// 接收数据
        /// </summary>
        /// <param name="session">接收数据的Session</param>
        /// <param name="data">数据</param>
        /// <param name="fileDownloadPath">如果是触发文件传输请求，设置文件保存路径函数</param>
        /// <returns></returns>
        public static (DataPackType PackType, byte[] Data, long DataAllLength, long RedeiverLength) RecieverData(TcpSocketSaeaSession session, byte[] data, Func<string, long, string> fileDownloadPath)
        {
            byte[] _data = null;
            long _dataAllLength = 0;
            long _receiverLength = 0;
            DataPackType _packType = DataPackType.DataError;
            _packType = (DataPackType)Enum.ToObject(typeof(DataPackType), data[0]);

            if (_packType == DataPackType.DataOnePack)
            {
                //接收单数据包
                _packType = DataPackType.DataOnePack;
                int _dataLength = BitConverter.ToInt32(data, 1);
                _data = new byte[_dataLength];
                Array.Copy(data, 1 + sizeof(Int32), _data, 0, _dataLength);
                _dataAllLength = _dataLength;
                _receiverLength = _dataLength;
            }
            else if (_packType == DataPackType.DataMultiplePack)
            {
                //接收分包数据
                _packType = DataPackType.DataMultiplePack;
                //取出分包唯一ID
                long _id = BitConverter.ToInt64(data, 1);
                //取出分包数据起始位置
                long _dataReceiver = BitConverter.ToInt64(data, 1 + sizeof(Int64));
                long _dataSize = 0;

                if (_dataReceiver == 0)
                {
                    //第一个包获取数据包总大小
                    _dataSize = BitConverter.ToInt64(data, 1 + sizeof(Int64) + sizeof(Int64));
                    _data = new byte[_dataSize];
                    DataMultiplePackList.TryAdd(_id, _data);
                    Array.Copy(data, 1 + sizeof(Int64) + sizeof(Int64) + sizeof(Int64), _data, 0, data.Length - 1 - sizeof(Int64) - sizeof(Int64) - sizeof(Int64));
                    _dataAllLength = _dataSize;
                    _receiverLength = _dataReceiver + data.Length - 1 - sizeof(Int64) - sizeof(Int64) - sizeof(Int64);
                }
                else
                {
                    //第二个包开始 
                    _data = DataMultiplePackList.GetValueOrDefault(_id);
                    Array.Copy(data, 1 + sizeof(Int64) + sizeof(Int64), _data, _dataReceiver, data.Length - 1 - sizeof(Int64) - sizeof(Int64));
                    _dataAllLength = _data.Length;
                    _receiverLength = _dataReceiver + data.Length - 1 - sizeof(Int64) - sizeof(Int64);
                    if (_dataAllLength == _receiverLength)
                    {
                        //接收结束
                        DataMultiplePackList.TryRemove(_id, out _data);
#if DEBUG
                        LogHelper.WriteLogToFile("Socket", DateTime.Now.ToString("HH:mm:ss.fff") + " " + "接收分包数据完毕:[" + _id + "]" + (session.Socket.RemoteEndPoint as IPEndPoint).Address.ToString() + ":" + (session.Socket.RemoteEndPoint as IPEndPoint).Port.ToString() + "，已接受数据量:" + _receiverLength.ToString());
#endif
                        return (_packType, _data, _dataAllLength, _receiverLength);
                    }

                }
                //接收完成，请求接收下一部分数据
                //数据格式：数据类型标识+唯一编号+已接收的数据长度
                byte[] _sendData = new byte[1 + sizeof(Int64) + sizeof(Int64)];
                _sendData[0] = Convert.ToByte(DataPackType.DataMultiplePackRequest);
                BitConverter.GetBytes(_id).CopyTo(_sendData, 1);
                BitConverter.GetBytes(_receiverLength).CopyTo(_sendData, 1 + sizeof(Int64));
#if DEBUG
                LogHelper.WriteLogToFile("Socket", DateTime.Now.ToString("HH:mm:ss.fff") + " " + "接收分包数据:[" + _id + "]" + (session.Socket.RemoteEndPoint as IPEndPoint).Address.ToString() + ":" + (session.Socket.RemoteEndPoint as IPEndPoint).Port.ToString() + "，已接受数据量:" + _receiverLength.ToString());

#endif
                session.SendAsync(_sendData);
            }
            else if (_packType == DataPackType.DataMultiplePackRequest)
            {
                //收到分包数据发送请求
                //取出分包唯一ID
                long _id = BitConverter.ToInt64(data, 1);
                //取出分包数据起始位置
                long _dataReceiver = BitConverter.ToInt64(data, 1 + sizeof(Int64));

                SendData(session, null, _id, _dataReceiver);
            }
            else if (_packType == DataPackType.FileInfo)
            {
                //接收到文件传输请求
                _packType = DataPackType.FileInfo;
                //取出分包唯一ID
                long _id = BitConverter.ToInt64(data, 1);
                //取出文件总大小
                long _dataReceiver = BitConverter.ToInt64(data, 1 + sizeof(Int64));
                //取出文件信息json字符串
                byte[] _bServerFileInfo = new byte[data.Length - (1 + sizeof(Int64) + sizeof(Int64))];
                Array.Copy(data, 1 + sizeof(Int64) + sizeof(Int64), _bServerFileInfo, 0, _bServerFileInfo.Length);
                string _serverFileInfo = Encoding.UTF8.GetString(_bServerFileInfo);
                string _serverFilePath = string.Empty;
                string _fileMD5 = string.Empty;
                string _clientFilePath = string.Empty;
                DateTime _lastModifiedTime = DateTime.MinValue;

                if (!string.IsNullOrWhiteSpace(_serverFileInfo))
                {
                    JsonHelper _jFileInfo = new JsonHelper(_serverFileInfo);
                    _serverFilePath = _jFileInfo.GetVar("FilePath");
                    _fileMD5 = _jFileInfo.GetVar("FileMD5");
                    _lastModifiedTime = Convert.ToDateTime(_jFileInfo.GetVar("LastModifiedTime"));


                }

                //从缓存中获取，判断是否为已经开始下载的文件
                FileDownloadInfo _fileDownloadInfo = CacheHelper.CacheGet("FileDownloadInfoClient_" + _id.ToString()) as FileDownloadInfo;
                if (_fileDownloadInfo != null)
                {
                    if (_serverFilePath != _fileDownloadInfo.ServerFilePath || _dataReceiver != _fileDownloadInfo.FileSize || _lastModifiedTime != _fileDownloadInfo.LastModifiedTime)
                    {
                        _fileDownloadInfo = null;
                    }
                }

                if (_fileDownloadInfo == null)
                {

                    _clientFilePath = fileDownloadPath(_serverFilePath, _dataReceiver);
                    if (string.IsNullOrWhiteSpace(_clientFilePath))
                    {
                        throw new Exception("保存文件路径不可为空");
                    }

                    _fileDownloadInfo = new FileDownloadInfo();

                    _fileDownloadInfo.ID = _id;
                    _fileDownloadInfo.ServerFilePath = _serverFilePath;
                    _fileDownloadInfo.FileSize = _dataReceiver;
                    _fileDownloadInfo.LastModifiedTime = _lastModifiedTime;
                    if (!string.IsNullOrWhiteSpace(_clientFilePath))
                    {
                        _fileDownloadInfo.ClientFilePath = _clientFilePath;
                    }

                    string _tempFileName = _fileDownloadInfo.ClientFilePath.Substring(0, _fileDownloadInfo.ClientFilePath.Length - FileHelper.GetFileExt(_fileDownloadInfo.ClientFilePath).Length - 1);


                    string _sfileInfo = new JsonHelper().AddVar("FilePath", _serverFilePath).AddVar("FileSize", _dataReceiver).AddVar("LastModifiedTime", _lastModifiedTime).JsonStr;
                    if (File.Exists(_tempFileName + ".f"))
                    {
                        //判断已存在的文件是否为要下载的文件
                        JsonHelper _jf = new JsonHelper(FileHelper.FileTextRead(_tempFileName + ".f"));
                        if (_serverFilePath != _jf.GetVar("FilePath") || _dataReceiver != Convert.ToInt64(_jf.GetVar("FileSize")) || _lastModifiedTime != Convert.ToDateTime(_jf.GetVar("LastModifiedTime")))
                        {
                            FileHelper.DeleteFile(_tempFileName + ".f");
                            if (File.Exists(_tempFileName + ".tmp"))
                            {
                                FileHelper.DeleteFile(_tempFileName + ".tmp");
                            }
                            FileHelper.FileTextWrite(_tempFileName + ".f", _sfileInfo);
                        }
                    }
                    else
                    {
                        if (File.Exists(_tempFileName + ".tmp"))
                        {
                            FileHelper.DeleteFile(_tempFileName + ".tmp");
                        }
                        FileHelper.FileTextWrite(_tempFileName + ".f", _sfileInfo);
                    }

                    if (!Directory.Exists(FileHelper.GetFileDirectoryName(_tempFileName + ".tmp")))
                    {
                        Directory.CreateDirectory(FileHelper.GetFileDirectoryName(_tempFileName + ".tmp"));
                    }

                    //创建保存文件的文件流
                    _fileDownloadInfo.FileDownloadStream = new FileStream(_tempFileName + ".tmp", FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None);

                    //将文件信息及文件流放入缓存
                    CacheHelper.CacheAdd("FileDownloadInfoClient_" + _fileDownloadInfo.ID, _fileDownloadInfo, null, 60 * 5, (cacheKey, cacheValue) =>
                    {
                        _fileDownloadInfo = cacheValue as FileDownloadInfo;
                        if (_fileDownloadInfo.FileDownloadStream != null)
                        {
                            _fileDownloadInfo.FileDownloadStream.Close();
                        }
                    });
                }
                //发送请求文件内容数据
                //格式为  数据类型+传输ID+文件流长度(同已接收数据的长度)
                byte[] _sendData = new byte[1 + sizeof(Int64) + sizeof(Int64)];
                _sendData[0] = Convert.ToByte(DataPackType.FileDataPackRequest);
                BitConverter.GetBytes(_id).CopyTo(_sendData, 1);
                BitConverter.GetBytes(_fileDownloadInfo.FileDownloadStream.Length).CopyTo(_sendData, 1 + sizeof(Int64));
                session.SendAsync(_sendData);

                _data = Encoding.UTF8.GetBytes(_serverFileInfo);
                _dataAllLength = _dataReceiver;
                _receiverLength = _fileDownloadInfo.FileDownloadStream.Length;

            }
            else if (_packType == DataPackType.FileDataPackRequest)
            {
                //收到请求文件内容数据的请求 
                _packType = DataPackType.FileDataPackRequest;
                //取出分包唯一ID
                long _id = BitConverter.ToInt64(data, 1);
                //取出分包数据起始位置
                long _dataReceiver = BitConverter.ToInt64(data, 1 + sizeof(Int64));


                //从缓存中获取，判断是否为已经开始下载的文件
                FileDownloadInfo _fileDownloadInfo = CacheHelper.CacheGet("FileDownloadInfo_" + _id.ToString()) as FileDownloadInfo;
                if (_fileDownloadInfo != null)
                {
                    long _dataSize = 0;
                    if (_fileDownloadInfo.FileDownloadStream.Length - _dataReceiver + (1 + sizeof(Int64) + sizeof(Int64)) > DataPackSize)
                    {
                        _dataSize = DataPackSize;
                    }
                    else
                    {
                        _dataSize = _fileDownloadInfo.FileDownloadStream.Length - _dataReceiver + (1 + sizeof(Int64) + sizeof(Int64));
                    }

                    byte[] _sendData = new byte[_dataSize];
                    _sendData[0] = Convert.ToByte(DataPackType.FileDataPack);
                    BitConverter.GetBytes(_id).CopyTo(_sendData, 1);
                    BitConverter.GetBytes(_dataReceiver).CopyTo(_sendData, 1 + sizeof(Int64));
                    byte[] _fileData = new byte[_dataSize - (1 + sizeof(Int64) + sizeof(Int64))];
                    _fileDownloadInfo.FileDownloadStream.Seek(_dataReceiver, SeekOrigin.Begin);
                    _fileDownloadInfo.FileDownloadStream.Read(_fileData, 0, _fileData.Length);
                    Array.Copy(_fileData, 0, _sendData, 1 + sizeof(Int64) + sizeof(Int64), _fileData.Length);

                    session.SendAsync(_sendData);

                }
                else
                {
                    //下载文件缓存失效，返回下载超时
                    byte[] _sendData = new byte[1 + sizeof(Int64)];
                    _sendData[0] = Convert.ToByte(DataPackType.FileDataTimeOut);
                    BitConverter.GetBytes(_id).CopyTo(_sendData, 1);
                    session.SendAsync(_sendData);
                }



            }
            else if (_packType == DataPackType.FileDataPack)
            {
                //收到文件数据
                _packType = DataPackType.FileDataPack;
                //取出分包唯一ID
                long _id = BitConverter.ToInt64(data, 1);
                //取出数据起始位置
                long _dataReceiver = BitConverter.ToInt64(data, 1 + sizeof(Int64));

                FileDownloadInfo _fileDownloadInfo = CacheHelper.CacheGet("FileDownloadInfoClient_" + _id.ToString()) as FileDownloadInfo;
                if (_fileDownloadInfo == null)
                {
                    throw new Exception("接收文件数据超时");
                }

                byte[] _fileData = new byte[data.Length - (1 + sizeof(Int64) + sizeof(Int64))];
                Array.Copy(data, 1 + sizeof(Int64) + sizeof(Int64), _fileData, 0, _fileData.Length);

                _fileDownloadInfo.FileDownloadStream.Seek(_dataReceiver, SeekOrigin.Begin);
                _fileDownloadInfo.FileDownloadStream.Write(_fileData, 0, _fileData.Length);


                _dataAllLength = _fileDownloadInfo.FileSize;
                _receiverLength = _fileDownloadInfo.FileDownloadStream.Length; 

                _data = Encoding.UTF8.GetBytes(_fileDownloadInfo.ClientFilePath);

                if (_dataAllLength != _receiverLength)
                {
                    byte[] _sendData = new byte[1 + sizeof(Int64) + sizeof(Int64)];
                    _sendData[0] = Convert.ToByte(DataPackType.FileDataPackRequest);
                    BitConverter.GetBytes(_id).CopyTo(_sendData, 1);
                    BitConverter.GetBytes(_receiverLength).CopyTo(_sendData, 1 + sizeof(Int64));
                    session.SendAsync(_sendData);
                }
                else
                {
                    _fileDownloadInfo.FileDownloadStream.Close();

                    string _tempFileName = _fileDownloadInfo.ClientFilePath.Substring(0, _fileDownloadInfo.ClientFilePath.Length - FileHelper.GetFileExt(_fileDownloadInfo.ClientFilePath).Length - 1);

                    if (File.Exists(_fileDownloadInfo.ClientFilePath))
                    {
                        File.Delete(_fileDownloadInfo.ClientFilePath);
                    }

                    // 重命名文件
                    File.Move(_tempFileName + ".tmp", _fileDownloadInfo.ClientFilePath);

                    FileHelper.SetFileModifiedTime(_fileDownloadInfo.ClientFilePath, _fileDownloadInfo.LastModifiedTime);

                    if (File.Exists(_tempFileName + ".f"))
                    {
                        FileHelper.DeleteFile(_tempFileName + ".f");
                    }
                }

            }


            return (_packType, _data, _dataAllLength, _receiverLength);
        }



    }

    /// <summary>
    /// 下载文件信息
    /// </summary>
    public class FileDownloadInfo
    {
        /// <summary>
        /// 下载任务唯一ID
        /// </summary>
        public long ID { get; set; } = 0;

        /// <summary>
        /// 下载文件路径
        /// </summary>
        public string ServerFilePath { get; set; } = "";

        /// <summary>
        /// 客户端保存文件路径
        /// </summary>
        public string ClientFilePath { get; set; } = "";

        /// <summary>
        /// 文件大小
        /// </summary>
        public long FileSize { get; set; } = 0;

        /// <summary>
        /// 最后修改时间
        /// </summary>
        public DateTime LastModifiedTime { get; set; }

        /// <summary>
        /// 文件流
        /// </summary>
        public FileStream FileDownloadStream { get; set; }

    }


}
